/**
 * 
 */
package matheus.tp01cg.objetosdedesenho.recorte;

import android.util.Log;
import matheus.tp01cg.objetosdedesenho.Coords;
import matheus.tp01cg.objetosdedesenho.Reta;

/**
 * Recorte de retas utilizando LiangBarsky
 * 
 * @author matheus
 * 
 */
public class LiangBarsky extends Recorte {

	/**
	 * @param limMin
	 * @param limMax
	 */
	public LiangBarsky(Coords limMin, Coords limMax) {
		super(limMin, limMax);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * matheus.tp01cg.objetosdedesenho.recorte.Recorte#recortaReta(matheus.tp01cg
	 * .objetosdedesenho.Reta)
	 */
	@Override
	protected Reta recortaReta(Reta reta) {
		Reta retorno = null;
		try {
			retorno = (Reta) reta.clone();
			if (retorno.nula)
				return retorno;
			double x1, y1, x2, y2;
			x1 = reta.getPontoInicial().x;
			y1 = reta.getPontoInicial().y;
			x2 = reta.getPontoFinal().x;
			y2 = reta.getPontoFinal().y;
			double dx, dy;
			DoubleRef u1 = new DoubleRef(0.0);
			DoubleRef u2 = new DoubleRef(1.0);
			dx = x2 - x1;
			dy = y2 - y1;
			retorno.nula = true;
			if (clipTest(dx * -1.0, x1 - limMin.x, u1, u2)) {
				if (clipTest(dx, limMax.x - x1, u1, u2)) {
					if (clipTest(dy * -1, y1 - limMin.y, u1, u2)) {
						if (clipTest(dy, limMax.y - y1, u1, u2)) {
							if (u2.value < 1.0) {
								x2 = x1 + u2.value * dx;
								y2 = y1 + u2.value * dy;
							}
							if (u1.value > 0.0) {
								x1 = x1 + u1.value * dx;
								y1 = y1 + u1.value * dy;
							}
							retorno.getPontoInicial().x = (int) Math.round(x1);
							retorno.getPontoInicial().y = (int) Math.round(y1);
							retorno.getPontoFinal().x = (int) Math.round(x2);
							retorno.getPontoFinal().y = (int) Math.round(y2);
							retorno.nula = false;
						}
					}
				}
			}
		} catch (Exception e) {
			Log.d(null, null, e);
		}
		return retorno;
	}

	private boolean clipTest(double p, double q, DoubleRef u1, DoubleRef u2) {
		boolean retorno = true;
		double r;
		if (p < 0.0) { // fora para dentro
			r = q / p;
			if (r > u2.value) {
				retorno = false;
			} else if (r > u1.value) {
				u1.value = r;
			}
		} else if (p > 0.0) { // dentro para fora
			r = q / p;
			if (r < u1.value) {
				retorno = false;
			} else if (r < u2.value)
				u2.value = r;
		} else if (q < 0.0) {
			retorno = false;
		}
		return retorno;
	}

	private class DoubleRef {
		double value;

		public DoubleRef(double value) {
			this.value = value;
		}
	}
}
